package com.info.zhiduoduo.shiro.filter;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Sets;
import com.info.zhiduoduo.common.constants.SmartResult;
import com.info.zhiduoduo.common.constants.StatusMsg;
import com.info.zhiduoduo.common.utils.ContextUtil;
import com.info.zhiduoduo.common.utils.HttpUtil;
import com.info.zhiduoduo.common.utils.LogUtil;
import com.info.zhiduoduo.repository.entity.system.SystemManager;
import com.info.zhiduoduo.repository.mapper.system.ManagerMapper;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;

import java.io.IOException;
import java.util.Set;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class URLPathMatchingFilter extends AccessControlFilter {

	private static final Set<String> allowUrlSet = Sets.newHashSet();

	static {
		// allowUrlSet.add("/sys/login");
		allowUrlSet.add("/sys/updatepassword");
		allowUrlSet.add("/sys/queryTradecategoryOne");
		allowUrlSet.add("/sys/queryTradecategoryTwo");
		allowUrlSet.add("/sys/getTradecategoryTwoById");
		allowUrlSet.add("/sys/getTradeCategory");
	}

	/**
	 * 当isAccessAllowed返回false，会去请求onAccessDenied方法，返回true会去请求具体的方法
	 * 因为isAccessAllowed返回false不会直接返回到前端，所以不能处理具体的业务逻辑
	 *
	 * @param request
	 * @param response
	 * @param mappedValue
	 * @return
	 */
	@Override
	protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
		return false;
	}

	/**
	 * 处理具体的业务逻辑
	 *
	 * @param request
	 * @param response
	 * @return
	 */
	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
		//判断是不是OPTIONS，是OPTIONS请求直接返回
		if (HttpUtil.processOptions((HttpServletRequest) request, (HttpServletResponse) response)) {
			LogUtil.info("onAccessDenied()--->OPTIONS请求,直接返回！");
			return false;
		}
		//获取请求的接口
		String requestURL = getPathWithinApplication(request);
		LogUtil.info("onAccessDenied()--->接口URL：" + requestURL);
		//获取Shiro客户端
		Subject subject = SecurityUtils.getSubject();
		//判断是否登录
		if (allowUrlSet.contains(requestURL)) {
		    //匿名访问的接口，直接允许访问。
			return true;
		} else if (!subject.isAuthenticated()) {
			errorMessage(response, StatusMsg.StatusMsg_126);
			return false;
		} else {
			//动态权限校验
			SystemManager user = (SystemManager) subject.getPrincipal();
			String userName = user.getLoginname();
			ManagerMapper managerMapper = ContextUtil.getBean(ManagerMapper.class);
			// RoleUrlMapper roleUrlMapper = ContextUtil.getBean(RoleUrlMapper.class);
			SystemManager manager = managerMapper.getManager(userName);

			//以下是api接口权限验证，暂时不做
			// List<String> roleUrl = roleUrlMapper.findRoleUrl(manager.getRoleid());
			// if (!roleUrl.contains(requestURL)) {
			//     errorMessage(response,StateMsg.StatusMsg_203);
			//     return false;
			// }
		}
		//刷新token有效时间(shiro+redis会自动刷新时间，先将代码保留，后面可以删除)
		//        String token = WebUtils.toHttp(request).getHeader("Authorization");
		//        if(StringUtils.isEmpty(token)){
		//            errorMessage(response,StateMsg.StatusMsg_204);
		//            return false;
		//        }
		//        RedisUtil redisUtil = SpringUtil.getBean(RedisUtil.class);
		//        long time =  redisUtil.getExpire(KEY + token);
		//        if(0 > time){
		//            errorMessage(response,StateMsg.StatusMsg_146);
		//            return false;
		//        } else {
		//            //有效时间小于10分钟，重新刷新token有效时间
		//            if(600 > time){
		//                long effectiveTime = 1800;
		//                boolean b = redisUtil.expire(KEY + token,effectiveTime);
		//                if(!b){
		//                    errorMessage(response,StateMsg.StatusMsg_205);
		//                    return false;
		//                }
		//            }
		//        }
		return true;
	}

	/**
	 * 错误返回
	 *
	 * @param response
	 * @param statusMsg
	 * @throws IOException
	 */
	private void errorMessage(ServletResponse response, StatusMsg statusMsg) throws IOException {
		response.setContentType("application/json; charset=utf-8");
		SmartResult smartResult = new SmartResult();
		smartResult.setStateMsg(statusMsg);
		response.getWriter().write(JSONObject.toJSONString(smartResult));
		response.getWriter().flush();
	}
}

